#include <stdio.h>

#define LG_CORE

#include "lg_material.h"

static void
freeMaterial(LGRef* ref) {
	LGMaterial* material = (LGMaterial*)ref;
	lgReleaseRef(material->shader);
	LGUniform* u;
	for (unsigned i = 0; i < material->count; i++) {
		u = &material->uniforms[i];
		switch (u->type) {
		case LG_TCANVAS:
			lgReleaseRef(u->canvas);
			break;
		case LG_TTEXTURE:
			lgReleaseRef(u->tex);
			break;
		}
	}
	material->count = 0;
}

LG_API LGMaterial*
lgNewMaterial(LGShader* shader) {
	LGMaterial* material = lgNewRef(sizeof(LGMaterial), freeMaterial);
	material->depthTest = LG_DEPTH_TEST_ALWAYS;
	material->drawType = LG_DRAW_TRIANGLES;
	lgRetainRef(shader);
	material->shader = shader;
	return material;
}

LG_API void
lgMaterialShader(LGMaterial* material, LGShader* shader) {
	if (material->shader == shader) {
		return;
	}
	lgReleaseRef(material->shader);
	lgRetainRef(shader);
	material->shader = shader;
}

LG_API unsigned
lgRegUniformF(LGMaterial* material, const char* name, LGFloat f) {
	int index = material->count++;
	LGUniform* u = &material->uniforms[index];
	u->f = f;
	u->type = LG_TFLOAT;
	sprintf_s(u->name, 128, "%s", name);
	return index;
}

LG_API unsigned
lgRegUniformV(LGMaterial* material, const char* name, LGVector* v) {
	int index = material->count++;
	LGUniform* u = &material->uniforms[index];
	u->v = *v;
	u->type = LG_TVECTOR;
	sprintf_s(u->name, 128, "%s", name);
	return index;
}

LG_API unsigned
lgRegUniformM(LGMaterial* material, const char* name, LGMatrix* m) {
	int index = material->count++;
	LGUniform* u = &material->uniforms[index];
	u->m = *m;
	u->type = LG_TMATRIX;
	sprintf_s(u->name, 128, "%s", name);
	return index;
}

LG_API unsigned
lgRegUniformTex(LGMaterial* material, const char* name, LGTexture* tex) {
	lgRetainRef(tex);
	int index = material->count++;
	LGUniform* u = &material->uniforms[index];
	u->tex = tex;
	u->type = LG_TTEXTURE;
	sprintf_s(u->name, 128, "%s", name);
	return index;
}

LG_API unsigned
lgRegUniformCanvas(LGMaterial* material, const char* name, LGCanvas* canvas) {
	lgRetainRef(canvas);
	int index = material->count++;
	LGUniform* u = &material->uniforms[index];
	u->canvas = canvas;
	u->type = LG_TCANVAS;
	sprintf_s(u->name, 128, "%s", name);
	return index;
}

LG_API void
lgSetUniformF(LGMaterial* material, unsigned index, LGFloat f) {
	if (index >= material->count) {
		return;
	}
	LGUniform* u = &material->uniforms[index];
	if (u->type != LG_TFLOAT) {
		return;
	}
	u->f = f;
}

LG_API void
lgSetUniformV(LGMaterial* material, unsigned index, LGVector* v) {
	if (index >= material->count) {
		return;
	}
	LGUniform* u = &material->uniforms[index];
	if (u->type != LG_TVECTOR) {
		return;
	}
	u->v = *v;
}

LG_API void
lgSetUniformM(LGMaterial* material, unsigned index, LGMatrix* m) {
	if (index >= material->count) {
		return;
	}
	LGUniform* u = &material->uniforms[index];
	if (u->type != LG_TMATRIX) {
		return;
	}
	u->m = *m;
}

LG_API void
lgSetUniformTex(LGMaterial* material, unsigned index, LGTexture* tex) {
	if (index >= material->count) {
		return;
	}
	LGUniform* u = &material->uniforms[index];
	if (u->type != LG_TTEXTURE) {
		return;
	}
	if (u->tex == tex) {
		return;
	}
	lgReleaseRef(u->tex);
	lgRetainRef(tex);
	u->tex = tex;
}

LG_API void
lgSetUniformCanvas(LGMaterial* material, unsigned index, LGCanvas* canvas) {
	if (index >= material->count) {
		return;
	}
	LGUniform* u = &material->uniforms[index];
	if (u->type != LG_TCANVAS) {
		return;
	}
	if (u->canvas == canvas) {
		return;
	}
	lgReleaseRef(u->canvas);
	lgRetainRef(canvas);
	u->canvas = canvas;
}

LG_API void
lgSetDepthTest(LGMaterial* material, LGDepthTest depthTest) {
	material->depthTest = depthTest;
}

LG_API void
lgSetDrawType(LGMaterial* material, LGDrawType type) {
	material->drawType = type;
}